package io.openkunlun.javarpc;

import com.caucho.hessian.io.Hessian2Input;
import com.caucho.hessian.io.Hessian2Output;
import com.caucho.hessian.io.SerializerFactory;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;

public final class RpcErrors {

    private static final ThreadLocal<SerializerFactory> FACTORY_LOCAL = ThreadLocal.withInitial(SerializerFactory::new);

    /**
     * @param obj
     * @return
     */
    public static byte[] pack(RuntimeException obj) {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        Hessian2Output hout = null;
        try {
            hout = new Hessian2Output(out);
            hout.setSerializerFactory(FACTORY_LOCAL.get());
            hout.setCloseStreamOnClose(true);
            hout.startMessage();
            hout.writeObject(obj);
            hout.completeMessage();
            hout.flush();
            return out.toByteArray();
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (null != hout) {
                try {
                    hout.close();
                } catch (Exception e) {
                    // ignore
                }
            }
        }
    }

    /**
     * @param bytes
     * @return
     */
    public static RuntimeException unpack(byte[] bytes) {

        Hessian2Input hin = null;
        try {
            hin = new Hessian2Input(new ByteArrayInputStream(bytes));
            hin.setSerializerFactory(FACTORY_LOCAL.get());
            hin.setCloseStreamOnClose(true);
            hin.startMessage();
            Object result = hin.readObject(Throwable.class);
            hin.completeMessage();

            if (result instanceof RuntimeException) {
                return (RuntimeException) result;
            }
            return new RuntimeException((Throwable) result);
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (null != hin) {
                try {
                    hin.close();
                } catch (Exception e) {
                    // ignore
                }
            }
        }
    }

    private RpcErrors() {
    }
}
